package com.amon.amonplayer.watchdog;

import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;

import java.util.List;

public class ANRWatchDog implements Runnable {
    private static final String TAG = "ANRWatchDog";
    private static final long CHECK_INTERVAL = 5000L;
    private final Handler mAnrHandler;
    private final HandlerChecker mHandlerChecker;
    private Context mContext;

    public ANRWatchDog(Context mContext) {
        mAnrHandler = new Handler(ThreadManager.getAnrWatchDogLooper());
        Handler mainHandler = new Handler(Looper.getMainLooper());
        mHandlerChecker = new HandlerChecker(mainHandler);
    }

    public void start() {
        mAnrHandler.post(this);
    }

    @Override
    public void run() {
        synchronized (this) {
            mHandlerChecker.scheduleCheckLooked();

            long start = SystemClock.uptimeMillis();
            long timeout = CHECK_INTERVAL;
            while (timeout > 0) {
                try {
                    wait(timeout);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Log.wtf(TAG, e);
                }
                timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
            }
            if (mHandlerChecker.isBlocked()) {
                Log.e(TAG, "可能存在ANR");
                doubtANR();
                mHandlerChecker.restoreBlocked();
            }
            mAnrHandler.post(this);
        }
    }

    private void doubtANR() {
        ThreadManager.run(() -> {
            ActivityManager.ProcessErrorStateInfo processErrorStatInfo = getErrorInfo(mContext);
            if (processErrorStatInfo != null) {
                Log.e(TAG, "" + processErrorStatInfo);
//                RuntimeException e = new RuntimeException(processErrorStatInfo.shortMsg);
//                e.setStackTrace(mHandlerChecker.getThread().);
            }
        });
    }

    private ActivityManager.ProcessErrorStateInfo getErrorInfo(Context context) {
        try {
            final long sleepTime = 500L;
            final long loop = 20;
            long times = 0;
            do {
                ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
                List<ActivityManager.ProcessErrorStateInfo> processErrorStateInfoList = activityManager.getProcessesInErrorState();
                if (processErrorStateInfoList != null) {
                    for (ActivityManager.ProcessErrorStateInfo processErrorStateInfo : processErrorStateInfoList) {
                        if (processErrorStateInfo.condition == ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING) {
                            return processErrorStateInfo;
                        }
                    }
                }
                Thread.sleep(sleepTime);
            } while (times++ < loop);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static final class HandlerChecker implements Runnable {
        private final Handler mHandler;
        private boolean mCompleted = true;

        private HandlerChecker(Handler handler) {
            this.mHandler = handler;
        }

        @Override
        public void run() {
            mCompleted = true;
        }

        public void scheduleCheckLooked() {
            if (!mCompleted) {
                return;
            }
            mCompleted = false;
            mHandler.postAtFrontOfQueue(this);
        }

        public boolean isBlocked() {
            return !mCompleted;
        }

        public void restoreBlocked() {
            mCompleted = false;
        }
    }
}
